package com.xuxy.Controller;


import com.xuxy.entity.SysMenu;
import com.xuxy.service.SysMenuService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/sys_menu")
@RequiredArgsConstructor
public class SysMenuController {

    private final SysMenuService menuService;


    @GetMapping("/tree")
    public List<SysMenu> tree() {
        return convertToTree(menuService.list());
    }

    @GetMapping("/tree_diagram/{id}")
    public List<SysMenu> getTreeDiagram(@PathVariable Integer id) {
        List<SysMenu> all = convertToTree(menuService.list());

        // 存放结果集的集合
        List<SysMenu> res = new ArrayList<>();
        // 存放父节点下的子结果集的集合
        List<SysMenu> pres = new ArrayList<>();

        return convertToTree(getList(all, id, res, pres).stream().distinct().collect(Collectors.toList()));
    }

    @GetMapping("/tree_diagram2/{id}")
    public List<SysMenu> getTreeDiagram2(@PathVariable Integer id) {
        List<SysMenu> all = convertToTree(menuService.list());

        // 存放结果集的集合
        List<SysMenu> res = new ArrayList<>();
        // 存放父节点下的子结果集的集合
        List<SysMenu> pres = new ArrayList<>();
        // 存放目标对象
        SysMenu sysMenu = new SysMenu();

        return convertToTree(getList(all, id, res, pres, sysMenu).stream().distinct().collect(Collectors.toList()));
    }


    /**
     * 查找符合条件的集合
     * @param sysMenus 所有的集合
     * @param id 目标ID
     * @param res 结果集合
     * @param pres 某个父节点下的所有子节点集合
     * @return res
     */
    private List<SysMenu> getList(List<SysMenu> sysMenus, Integer id, List<SysMenu> res, List<SysMenu> pres) {
        SysMenu item = getItem(sysMenus, id);
        if (item != null && item.getParentId() != null && item.getParentId() != 0) {
            res.addAll(getItems(sysMenus, item.getParentId(), pres));
            return getList(sysMenus, item.getParentId(), res, pres);
        } else if (item != null && item.getParentId() != null && item.getParentId() == 0) {
            res.add(item);
        }
        return res;
    }

    private List<SysMenu> getList(List<SysMenu> sysMenus, Integer id, List<SysMenu> res, List<SysMenu> pres, SysMenu sysMenu) {
        SysMenu item = getItem(sysMenus, id, sysMenu);
        if (item != null && item.getParentId() != null && item.getParentId() != 0) {
            res.addAll(getItems(sysMenus, item.getParentId(), pres));
            return getList(sysMenus, item.getParentId(), res, pres);
        } else if (item != null && item.getParentId() != null && item.getParentId() == 0) {
            res.add(item);
        }
        return res;
    }

    /**
     * 根据 PID 查 所有子节点
     * @param sysMenus
     * @param parentId
     * @param res
     * @return
     */
    private List<SysMenu> getItems(List<SysMenu> sysMenus, Integer parentId, List<SysMenu> res) {
        Deque<List<SysMenu>> deque = new ArrayDeque<>();
        deque.offer(sysMenus);
        while (!deque.isEmpty()) {
            List<SysMenu> poll = deque.poll();
            for (SysMenu sysMenu : poll) {
                if (sysMenu != null && Objects.equals(parentId, sysMenu.getParentId())) {
                    res.add(sysMenu);
                }
                if (sysMenu != null && sysMenu.getChildren() != null) {
                    deque.offer(sysMenu.getChildren());
                }
            }
        }
        return res;
    }

    /**
     * 递归遍历查找目标节点
     * @param sysMenus list
     * @param id 目标节点
     * @param start 开始索引
     * @return SysMenu
     */
    private SysMenu getItem(List<SysMenu> sysMenus, Integer id, int start) {
        if (start >= sysMenus.size()) {
            return null;
        }
        SysMenu item = sysMenus.get(start);
        if (Objects.equals(id, item.getMenuId())) {
            return item;
        }
        if (!item.getChildren().isEmpty()) {
            return getItem(item.getChildren(), id, 0);
        }
        return getItem(sysMenus, id, start + 1);
    }

    /**
     * 递归查找目标节点
     * @param sysMenus 所有数据集合
     * @param id 目标节点
     * @param sysMenu 存放目标对象
     * @return SysMenu
     */
    private SysMenu getItem(List<SysMenu> sysMenus, Integer id, SysMenu sysMenu) {

        for (SysMenu menu : sysMenus) {
            if (Objects.equals(id, menu.getMenuId())) {
                sysMenu = menu;
                return sysMenu;
            } else {
                return getItem(menu.getChildren(), id, sysMenu);
            }
        }
        return sysMenu;
    }

    private SysMenu getItem(List<SysMenu> sysMenus, Integer id) {
        Deque<List<SysMenu>> deque = new ArrayDeque<>();
        deque.offer(sysMenus);

        while (!deque.isEmpty()) {
            List<SysMenu> poll = deque.poll();
            for (SysMenu sysMenu : poll) {
                if (sysMenu != null && Objects.equals(id, sysMenu.getMenuId())) {
                    return sysMenu;
                }
                if (sysMenu != null && sysMenu.getChildren() != null) {
                    deque.offer(sysMenu.getChildren());
                }
            }
        }
        return null;
    }


    /**
     * 把 集合 转换成 树
     * @param sysMenus 转换的集合
     * @return list 树
     */
    private List<SysMenu> convertToTree(List<SysMenu> sysMenus) {
        return sysMenus.stream()
                .filter(sysMenu -> sysMenu.getParentId() == 0)
                .peek(sysMenu -> sysMenu.setChildren(getChildren(sysMenu, sysMenus)))
                .collect(Collectors.toList());
    }

    /**
     * 递归获取子节点
     * @param root 目标节点
     * @param all list
     * @return list
     */
    private List<SysMenu> getChildren(SysMenu root, List<SysMenu> all) {
        return all.stream()
                .filter(sysMenu -> Objects.equals(sysMenu.getParentId(), root.getMenuId()))
                .peek(sysMenu -> sysMenu.setChildren(getChildren(sysMenu, all)))
                .collect(Collectors.toList());
    }


}
